//
//  AssetCollectionViewController.swift
//  GifUsage
//
//  Created by han on 2020/12/18.
//  Copyright © 2020 Ting Han. All rights reserved.
//

import UIKit
import Photos

class AssetCollectionViewController: UIViewController {
    
    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var flowLayout: UICollectionViewFlowLayout!
    
    var fetchResult:PHFetchResult<PHAsset>?
    private let imageManager = PHCachingImageManager()
    private var previousPreheatRect = CGRect.zero
    private var thumbnailSize: CGSize!
    
    var functionType: FunctionType = .imageToGIF
    
    var selectedItems = [Int]()
    
    var saveItem: UIBarButtonItem!
    var choseItem: UIBarButtonItem!
    var cancleItem: UIBarButtonItem!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupNavigationBar()
        resetCachedAsset()
        
        flowLayout.itemSize = itemSize
        flowLayout.minimumLineSpacing = 10
        flowLayout.minimumInteritemSpacing = 10
        let scale = UIScreen.main.scale
        thumbnailSize = CGSize(width: scale * itemSize.width, height: scale * itemSize.height)
        
        collectionView.register(ImageCell.self, forCellWithReuseIdentifier: "imageCell")
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        updateCachedAssets()
    }
    
    lazy var itemSize: CGSize = {
        let width = (view.bounds.width - 5 * 10) / 4
        return CGSize(width: width, height: width)
    }()
    
    private func setupNavigationBar() {
        
        saveItem = UIBarButtonItem(title: "下一步", style: .done, target: self, action: #selector(nextAction))
        choseItem = UIBarButtonItem(title: "全选", style: .done, target: self, action: #selector(editAction))
        cancleItem = UIBarButtonItem(title: "取消", style: .done, target: self, action: #selector(cancleAction))
      
        if functionType == .imageToGIF {
            navigationItem.title = ""
            navigationItem.rightBarButtonItems = [saveItem, choseItem, cancleItem ]
        }
        
        let left = UIBarButtonItem(image: UIImage(systemName: "chevron.backward"), style: .done, target: self, action: #selector(backAction))
        navigationItem.leftBarButtonItem = left
    }
    
    @objc func backAction() {
        navigationController?.popViewController(animated: true)
    }
    
    @objc func editAction() {
        selectedItems.removeAll()
        selectedItems.append(contentsOf: 0 ..< (fetchResult?.count ?? 0))
        collectionView.reloadData()
    }
    
    @objc func cancleAction() {
        selectedItems.removeAll()
        collectionView.reloadData()
    }
    
    @objc func nextAction() {
       let assets = selectedItems.compactMap({
            self.fetchResult?.object(at: $0)
        })
        let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "GIFEditorViewController") as! GIFEditorViewController
        vc.assets = assets
        navigationController?.pushViewController(vc, animated: true)
    }
    
}

extension AssetCollectionViewController {
    private func resetCachedAsset() {
        imageManager.stopCachingImagesForAllAssets()
        previousPreheatRect = .zero
    }
    
    private func updateCachedAssets() {
        guard isViewLoaded && view.window != nil else { return }
        
        let visiableRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
        let preheatRect = visiableRect.insetBy(dx: 0, dy: -0.5 * visiableRect.height)
        let delta = abs(preheatRect.midY - previousPreheatRect.midY)
        guard delta > view.bounds.height / 3.0 else { return }
        
        let (addedRects, removedRects) = differencesBetweenRects(previousPreheatRect, preheatRect)
        let addedAssets = addedRects
            .flatMap { rect in collectionView.indexPathsForElements(in: rect) }
            .map { indexPath in fetchResult!.object(at: indexPath.item) }
        let removedAssets = removedRects
            .flatMap { rect in collectionView.indexPathsForElements(in: rect) }
            .map { indexPath in fetchResult!.object(at: indexPath.item) }
        
        imageManager.startCachingImages(for: addedAssets, targetSize: thumbnailSize, contentMode: .aspectFill, options: nil)
        imageManager.stopCachingImages(for: removedAssets, targetSize: thumbnailSize, contentMode: .aspectFill, options: nil)
        
        previousPreheatRect = preheatRect
    }
    
    /// 计算两个rect的差异，添加一部分rect，然后删除一部分rect
    private func differencesBetweenRects(_ old: CGRect, _ new: CGRect) -> (added: [CGRect], removed: [CGRect]) {
        if old.intersects(new) {
            var added = [CGRect]()
            if new.maxY > old.maxY {
                added += [CGRect(x: new.origin.x, y: old.maxY,
                                    width: new.width, height: new.maxY - old.maxY)]
            }
            if old.minY > new.minY {
                added += [CGRect(x: new.origin.x, y: new.minY,
                                    width: new.width, height: old.minY - new.minY)]
            }
            var removed = [CGRect]()
            if new.maxY < old.maxY {
                removed += [CGRect(x: new.origin.x, y: new.maxY,
                                      width: new.width, height: old.maxY - new.maxY)]
            }
            if old.minY < new.minY {
                removed += [CGRect(x: new.origin.x, y: old.minY,
                                      width: new.width, height: new.minY - old.minY)]
            }
            return (added, removed)
        } else {
            return ([new], [old])
        }
    }
    
}

// MARK: UIScrollViewDelegate
extension AssetCollectionViewController {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        updateCachedAssets()
    }
}

extension AssetCollectionViewController: UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        fetchResult?.count ?? 0
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCell
        let asset = fetchResult![indexPath.item]
        cell.representedAssetIdentifier = asset.localIdentifier
        imageManager.requestImage(for: asset, targetSize: thumbnailSize, contentMode: .aspectFill, options: nil) { (image, _) in
            if cell.representedAssetIdentifier == asset.localIdentifier {
                cell.imageView.image = image
            }
        }
        cell.isChosed = selectedItems.contains(indexPath.item)
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return itemSize
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        collectionView.deselectItem(at: indexPath, animated: true)
        if functionType == .imageToGIF {
            if selectedItems.contains(indexPath.item) {
                selectedItems.remove(at: selectedItems.firstIndex(of: indexPath.item)!)
            } else {
                selectedItems.append(indexPath.item)
            }
            collectionView.reloadItems(at: [indexPath])
        } else if functionType == .gifToImage {
            let image = ImageGridViewController()
            image.gifAsset = fetchResult!.object(at: indexPath.row)
            navigationController?.pushViewController(image, animated: true)
        } else if functionType == .videoToGIF {
            let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "GIFEditorViewController") as! GIFEditorViewController
            vc.videoAsset = fetchResult!.object(at: indexPath.row)
            navigationController?.pushViewController(vc, animated: true)
        }
    }
}


class ImageCell: UICollectionViewCell {
    
    var representedAssetIdentifier: String?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    var isChosed: Bool = false {
        didSet {
            maskImageView.isHidden = !isChosed
        }
    }
    
    func commonInit() {
        contentView.addSubview(imageView)
        contentView.clipsToBounds = true
        contentView.addSubview(maskImageView)
    }
    lazy var imageView: UIImageView = {
        let view = UIImageView()
        view.contentMode = .scaleAspectFill
        return view
    }()
    
    lazy var maskImageView: UIImageView = {
        let view = UIImageView()
        view.contentMode = .scaleAspectFit
        view.image = UIImage(systemName: "checkmark.circle")
        view.isHidden = true
        return view
    }()
    
    override var frame: CGRect {
        didSet {
            contentView.frame = bounds
            imageView.frame = bounds
            maskImageView.frame = bounds
        }
    }
    
}

private extension UICollectionView {
    func indexPathsForElements(in rect: CGRect) -> [IndexPath] {
        let allLayoutAttributes = collectionViewLayout.layoutAttributesForElements(in: rect)!
        return allLayoutAttributes.map { $0.indexPath }
    }
}
